#include "ResourceManager.h"
#include "ticpp/ticpp.h"
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>

using namespace sf;
using namespace std;

boost::scoped_ptr<ResourceManager> ResourceManager::singleton;

ResourceManager::ResourceManager() {}

ResourceManager* ResourceManager::getInstance()
{
	if (!singleton) {
		singleton.reset(new ResourceManager());
	}
	return singleton.get();
}

Font* ResourceManager::loadFont(const string& fontName)
{
	map<string, boost::shared_ptr<Font>>::iterator it = fonts.find(fontName);
	if (it != fonts.end()) {
		return it->second.get();
	} else {
		boost::shared_ptr<Font> font(new Font());
		font->LoadFromFile(fontName);
		fonts[fontName] = font;
		return font.get();
	}
}

Image* ResourceManager::loadImage(const string& imageName)
{
	map<string, boost::shared_ptr<Image>>::iterator it = images.find(imageName);
	if (it != images.end()) {
		return it->second.get();
	} else {
		boost::shared_ptr<Image> image(new Image());
		image->LoadFromFile(imageName);
		images[imageName] = image;
		return image.get();
	}
}

vector<AnimationDefinition> ResourceManager::loadAnimationFromXML(const string& fileName)
{
	vector<AnimationDefinition> animationDefs;

    ticpp::Document doc(fileName);
    doc.LoadFile();
	ticpp::Iterator<ticpp::Element> animation;
	for (animation = animation.begin(doc.FirstChildElement()); animation != animation.end(); ++animation) {
		AnimationDefinition def;
		animation->FirstChild("name")->FirstChild()->ToText()->GetValue(&def.name);
		animation->FirstChild("fps")->FirstChild()->ToText()->GetValue(&def.fps);

		ticpp::Iterator<ticpp::Element> frame;
		for (frame = frame.begin(animation->FirstChild("frames")); frame != frame.end(); ++frame) {
			string frameValue = frame->FirstChild()->ToText()->Value();
			vector<string> tokens;
			boost::split(tokens, frameValue, boost::is_any_of(","));
			if (tokens.size() != 4) {
				throw exception("Incorrect file format.");
			}
			def.frames.push_back(IntRect(
				boost::lexical_cast<int>(tokens[0]),
				boost::lexical_cast<int>(tokens[1]), 
				boost::lexical_cast<int>(tokens[2]), 
				boost::lexical_cast<int>(tokens[3])
				));
		}
		animationDefs.push_back(def);
	}
	return animationDefs;
}

MapInfo ResourceManager::loadMapInfo(const string& mapName)
{
	return mapLoader.loadMapInfo(mapName);
}
